#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/prctl.h>

#include "cJSON.h"
#include "curl/curl.h"

#include "cicd_config.h"
#include "item_manager.h"
#include "msg_manager.h"
#include "message_queue.h"
#include "file_queue.h"
#include "compile_and_post_manager.h"
#include "cicd_common.h"
#include "file_delete_manager.h"

#define INIT_OK     0
#define INIT_FAILED 1

// 目前仅支持 单用户 单token 多仓库
char global_access_token[35] = { 0 };    // access token，当gitee更新后需要进行同步更新
char global_owner[50] = { 0 };           // 仓库所属的用户
char global_repo[20][50] = { 0 };        // 用户下要进行构建的仓库，最多监听20个仓库
char global_repo_counter = 0;            // 仓库个数

// 编译产物仓库
char global_output_repo[50] = { 0 };     // 产物仓库

// 是否多线程
int thread_able = 0;    // 0代表单线程，1代表多线程

// 通过json文件进行初始化
static int global_config_init() {
    cJSON *root = NULL;
    cJSON *json_tmp = NULL;
    cJSON *json_repo = NULL;
    FILE *fp = NULL;
    char buffer[1024] = { 0 };
    char config_file[256] = { 0 };
    char log_file[256] = { 0 };
    int buflen = 0;
    int ret = INIT_OK;
    char *tmp = NULL;
    int i;
    struct stat st;
    char *linux_user = getlogin();
    char root_floder[128] = { 0 };
    snprintf(root_floder, sizeof(root_floder), "/home/%s/.cicd", linux_user);

    if(access(root_floder, F_OK) != 0) {
        printf_error("There is no root floder. please use 'mkdir ~/.cicd'. Program exit.\n");
        return INIT_FAILED;
    }

    if(!(stat(root_floder, &st) == 0 && S_ISDIR(st.st_mode))) {
        printf_error("No access permissions for this file.\n");
        return INIT_FAILED;
    }

    // 组装配置文件地址
    snprintf(config_file, sizeof(config_file), "%s/config.json", root_floder);

    // 读取配置文件
    fp = fopen(config_file, "r");
    if(fp == NULL) {
        printf_error("No %s or no access permissions for this file or floder.\n", config_file);
        return INIT_FAILED;
    }
    buflen = fread(buffer, sizeof(char), sizeof(buffer), fp);
    fclose(fp);
    if(buflen == 0) {
        printf_error("Read file error. Please check your file.\n");
        return INIT_FAILED;
    }

    snprintf(log_file, sizeof(log_file), "%s/log.txt", root_floder);
    fp = NULL;
    fp = fopen(log_file, "a");
    if(fp == NULL) {
        printf_warning("Can not create or open ~/.cicd/log.txt\n");
    }
    else {
        setbuf(fp, NULL);
        fprintf(fp, "========================new open========================\n");
        set_log_file_handler(fp);
    }


    // json解析配置文件
    root = cJSON_Parse(buffer);
    if(NULL == root) {
        printf_error("JSON parse error, please check your config.json file\n");
        ret = INIT_FAILED;
        goto exit;
    }

    json_tmp = cJSON_GetObjectItem(root, "success");
    if(NULL == json_tmp) {
        flag_success_set(1);
    }
    else {
        flag_success_set(cJSON_IsTrue(json_tmp));
    }

    json_tmp = cJSON_GetObjectItem(root, "debug");
    if(NULL == json_tmp) {
        flag_debug_set(1);
    }
    else {
        flag_debug_set(cJSON_IsTrue(json_tmp));
    }

    json_tmp = cJSON_GetObjectItem(root, "info");
    if(NULL == json_tmp) {
        flag_info_set(1);
    }
    else {
        flag_info_set(cJSON_IsTrue(json_tmp));
    }

    printf_success("Read config file ok\n");
    printf_success("In configuration...\n");

    // 获得access token
    json_tmp = cJSON_GetObjectItem(root, "access_token");
    if(NULL == json_tmp) {
        printf_error("Config file without 'access_token'\n");
        ret = INIT_FAILED;
        goto exit;
    }
    tmp = cJSON_Print(json_tmp);
    strncpy(global_access_token, tmp, sizeof(global_access_token));
    free(tmp);
    delete_char(global_access_token, strlen(global_access_token), '\"');

    // 获得owner
    json_tmp = cJSON_GetObjectItem(root, "owner");
    if(NULL == json_tmp) {
        printf_error("Config file without 'owner'\n");
        ret = INIT_FAILED;
        goto exit;
    }
    tmp = cJSON_Print(json_tmp);
    strncpy(global_owner, tmp, sizeof(global_owner));
    free(tmp);
    delete_char(global_owner, strlen(global_owner), '\"');

    // 判断是否多线程
    json_tmp = cJSON_GetObjectItem(root, "thread");
    thread_able = cJSON_IsTrue(json_tmp);

    // 获得仓库信息
    json_tmp = cJSON_GetObjectItem(root, "repo");
    if(NULL == json_tmp) {
        printf_error("Config file without 'repo'\n");
        ret = INIT_FAILED;
        goto exit;
    }
    // 读取仓库个数
    global_repo_counter = cJSON_GetArraySize(json_tmp);
    if(global_repo_counter <= 0) {
        printf_error("There is no repo in config file. Provide at least one\n");
        ret = INIT_FAILED;
        goto exit;
    }

    // 逐个读取仓库名称
    for(i = 0; i < global_repo_counter; i++) {
        json_repo = cJSON_GetArrayItem(json_tmp, i);
        tmp = cJSON_Print(json_repo);
        strncpy(global_repo[i], tmp, sizeof(global_repo[i]));
        free(tmp);
        delete_char(global_repo[i], strlen(global_repo[i]), '\"');
    }

    // 获得产出物上传的仓库名
    json_tmp = cJSON_GetObjectItem(root, "output_repo");
    tmp = cJSON_Print(json_tmp);
    strncpy(global_output_repo, tmp, sizeof(global_output_repo));
    free(tmp);
    if(NULL == json_tmp) {
        printf_error("Config file without 'output_repo'\n");
        ret = INIT_FAILED;
        goto exit;
    }
    delete_char(global_output_repo, strlen(global_output_repo), '\"');

    // 成功的打印提示
    printf_success("Successfully configured\n");
    printf_info("access token: %s\n", global_access_token);
    printf_info("owner       : %s\n", global_owner);
    printf_info("total repo  : %d\n", global_repo_counter);
    for(i = 0; i < global_repo_counter; i++) {
        printf_info("repo %-7d: %s\n", i + 1, global_repo[i]);
    }
    printf_info("output repo : %s\n", global_output_repo);
    ret = INIT_OK;

exit:

    cJSON_Delete(root);

    return ret;
}

/**
 * @brief 配置替换
 * 
 * @return int 
 */
static int configuration_replacement() {
    cJSON *root = NULL;
    cJSON *json_tmp = NULL;
    cJSON *json_repo = NULL;
    FILE *fp = NULL;
    char buffer[1024] = { 0 };
    int buflen = 0;
    char config_file[256] = { 0 };
    char root_floder[128] = { 0 };
    char *tmp = NULL;
    struct stat st;
    int ret = INIT_OK;
    int i;

    snprintf(root_floder, sizeof(root_floder), "/home/%s/.cicd", getlogin());

    if(access(root_floder, F_OK) != 0) {
        printf_warning("In configuration replace. There is no root floder. please use 'mkdir ~/.cicd'.\n");
        return INIT_FAILED;
    }

    if(!(stat(root_floder, &st) == 0 && S_ISDIR(st.st_mode))) {
        printf_warning("In configuration replace. No access permissions for this file.\n");
        return INIT_FAILED;
    }

    // 组装配置文件地址
    snprintf(config_file, sizeof(config_file), "%s/config.json", root_floder);

    // 读取配置文件
    fp = fopen(config_file, "r");
    if(fp == NULL) {
        printf_warning("In configuration replace. No %s or no access permissions for this file or floder.\n", config_file);
        return INIT_FAILED;
    }
    buflen = fread(buffer, sizeof(char), sizeof(buffer), fp);
    fclose(fp);
    if(buflen == 0) {
        printf_warning("In configuration replace. Read file error. Please check your file.\n");
        return INIT_FAILED;
    }

    // json解析配置文件
    root = cJSON_Parse(buffer);
    if(NULL == root) {
        printf_warning("In configuration replace. JSON parse error, please check your config.json file\n");
        ret = INIT_FAILED;
        goto exit;
    }

    // 获得仓库信息
    json_tmp = cJSON_GetObjectItem(root, "repo");
    if(NULL == json_tmp) {
        printf_error("Config file without 'repo'\n");
        ret = INIT_FAILED;
        goto exit;
    }
    // 读取仓库个数
    global_repo_counter = cJSON_GetArraySize(json_tmp);
    if(global_repo_counter <= 0) {
        printf_error("There is no repo in config file. Provide at least one\n");
        ret = INIT_FAILED;
        goto exit;
    }

    // 逐个读取仓库名称
    for(i = 0; i < global_repo_counter; i++) {
        json_repo = cJSON_GetArrayItem(json_tmp, i);
        tmp = cJSON_Print(json_repo);
        strncpy(global_repo[i], tmp, sizeof(global_repo[i]));
        free(tmp);
        delete_char(global_repo[i], strlen(global_repo[i]), '\"');
    }

exit:

    cJSON_Delete(root);

    return ret;
}

// 每十秒进行一次监听并更新数据
void *thread_listen(void *p) {
    repo_handler *handler = NULL;
    int i;
    (void)p;
    repo_init(&handler);
    printf_debug("into thread_listen\n");
    prctl(PR_SET_NAME, "listen thread");
    while(1) {
        for(i = 0; i < global_repo_counter; i++) {
            printf_debug("start get repo %s branch status\n", global_repo[i]);
            msg_get_all_repo_status(global_access_token, global_owner, global_repo[i], handler);
            printf_debug("get repo %s branch status ok\n", global_repo[i]);
        }
        // printf("------------------------\n");
        // debug_show_all(handler);
        repo_update_mq(handler);
        // debug_show_all(handler);
        // debug_queue();
        // printf("------------------------\n");
        sleep(10);
        printf_debug("get repo status and update mq ok\n");
    }
    printf_debug("exit thread_listen\n");
}

// 每两秒进行一次编译询问
void *thread_compile(void *p) {
    (void)p;
    prctl(PR_SET_NAME, "compile thread");
    while(1) {
        printf_debug("test compile\n");
        compile_and_post_once();
        sleep(2);
    }
}

int main() {
    int ret = INIT_OK;
    pthread_t listen;
    pthread_t compile_and_post;

    ret = global_config_init();
    if(ret != INIT_OK) {
        return 0;
    }

    queue_compile_init();
    queue_file_init();

    if(thread_able) {
        pthread_create(&listen, NULL, thread_listen, NULL);
        pthread_create(&compile_and_post, NULL, thread_compile, NULL);

        prctl(PR_SET_NAME, "main thread");

        while(1) {
            file_delete_once();
            configuration_replacement();
            sleep(10);
        }
    }
    else {
        int i;
        repo_handler *handler = NULL;
        repo_init(&handler);
        while(1) {
            for(i = 0; i < global_repo_counter; i++) {
                printf_debug("start get repo %s branch status\n", global_repo[i]);
                msg_get_all_repo_status(global_access_token, global_owner, global_repo[i], handler);
                printf_debug("get repo %s branch status ok\n", global_repo[i]);
            }
            // printf("------------------------\n");
            // debug_show_all(handler);
            debug_show_all(handler);
            repo_update_mq(handler);
            debug_queue();
            // debug_show_all(handler);
            // debug_queue();
            // printf("------------------------\n");
            sleep(10);
            printf_debug("get repo status and update mq ok\n");
            
            // 编译一次
            compile_and_post_once();
            sleep(2);

            // 进行删除
            file_delete_once();
            sleep(3);

            // 配置替换
            configuration_replacement();
            sleep(1);
        }
    }
    return 0;
}
